#include "lisctl.h"
#include "hwctl.h"
#include "myposix.h"
#include "myface.h"
#include "myoled.h"
#include "wiringPi.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

static int oled_fd = -1;
static hw_pt devHead = NULL;

typedef struct rec_posix
{
    int recLen;
    unsigned char *recBuf;
    posix_pt recPosix;
} rec_node, *rec_pt;

int rec_init(void)
{
    devHead = lrled_add(devHead);
    devHead = beled_add(devHead);
    devHead = fan_add(devHead);
    devHead = alarm_add(devHead);
    devHead = lock_add(devHead);
    oled_fd = myoled_init();
    face_init();
    printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

void rec_final(void)
{
    face_fin();
    if (oled_fd > 0)
    {
        close(oled_fd);
        oled_fd = -1;
    }
}

void *handle_device(void *arg)
{
    pthread_detach(pthread_self());
    rec_pt rec_msg = (rec_pt)arg;
    if (NULL != rec_msg)
    {
        printf("%s|%s|%d:len = %d\n", __FILE__, __func__, __LINE__, rec_msg->recLen);
        printf("%s|%s|%d:handle->0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\n", __FILE__, __func__, __LINE__,
               rec_msg->recBuf[0], rec_msg->recBuf[1], rec_msg->recBuf[2], rec_msg->recBuf[3], rec_msg->recBuf[4], rec_msg->recBuf[5]);
    }
    // 设备处理
    hw_pt tmpHead = NULL;
    char mark[32] = {0};
    double result = 0.0;
    if (NULL != rec_msg && NULL != rec_msg->recBuf)
    {
        tmpHead = dev_find(devHead, rec_msg->recBuf[2]);
        printf("%s|%s|%d:tmpHead->dev_name = %s\n", __FILE__, __func__, __LINE__, tmpHead->dev_name);
    }
    if (NULL != tmpHead)
    {
        tmpHead->gpio_status = rec_msg->recBuf[3] == 0x00 ? LOW : HIGH;
        printf("%s|%s|%d:tmpHead->gpio_status = %d\n", __FILE__, __func__, __LINE__, tmpHead->gpio_status);

        if (1 == tmpHead->check_face_status && 0x00 == rec_msg->recBuf[3])
        {
            if ((result = face_search()) >= 0.6)
            {
                printf("%s|%s|%d:rec = %.2lf\n", __FILE__, __func__, __LINE__, result * 100);
                memset(mark, 0, sizeof(mark));
                strcpy(mark, "suceess");
                rec_msg->recBuf[2] = 0x33;
                set_dev(tmpHead);
            }
            else
            {
                printf("%s|%s|%d:rec = %lf\n", __FILE__, __func__, __LINE__, result * 100);
                memset(mark, 0, sizeof(mark));
                strcpy(mark, "fail");
                tmpHead->gpio_status = HIGH;
                rec_msg->recBuf[2] = 0x34;
            }
        }
        else
        {
            set_dev(tmpHead);
        }
    }

    oled_display(tmpHead);

    listen_pt lisHead = NULL;
    pthread_t tid = -1;
    if (NULL != rec_msg->recPosix->pHead)
    {
        lisHead = rec_msg->recPosix->pHead;
        while (NULL != lisHead)
        {
            if (strcmp(lisHead->listen_name, "voice") == 0)
            {
                if (0x00 == rec_msg->recBuf[2])
                {
                    break;
                }
                else if (((1 == tmpHead->voice_set_status) || (1 == tmpHead->check_face_status)) &&
                         (0x00 == rec_msg->recBuf[3]))
                {
                    if (1 == tmpHead->voice_set_status)
                    {
                        printf("%s|%s|%d:fire warning\n", __FILE__, __func__, __LINE__);
                        pthread_create(&tid, NULL, lisHead->set, (void *)rec_msg->recBuf);
                    }
                    else if (1 == tmpHead->check_face_status)
                    {
                        printf("%s|%s|%d:face comparing %s !\n", __FILE__, __func__, __LINE__, mark);
                        pthread_create(&tid, NULL, lisHead->set, (void *)rec_msg->recBuf);
                        if (result >= 0.6)
                        {
                            sleep(5);
                            rec_msg->recBuf[2] = 0x04;
                            rec_msg->recBuf[3] = 0x01;
                            posix_send(rec_msg->recPosix->mqd, rec_msg->recBuf, rec_msg->recLen);
                        }
                    }
                    break;
                }
            }
            lisHead = lisHead->next;
        }
    }
    pthread_exit(0);
}

void *rec_get(void *arg)
{
    struct mq_attr attr;
    rec_pt rec_msg = NULL;
    if (NULL != arg)
    {
        rec_msg = (rec_pt)malloc(sizeof(rec_node));
        rec_msg->recPosix = (posix_pt)arg;
        rec_msg->recLen = -1;
        rec_msg->recBuf = NULL;
    }
    else
    {
        pthread_exit(0);
    }
    if (-1 == mq_getattr(rec_msg->recPosix->mqd, &attr))
    {
        perror("mq_getattr");
        pthread_exit(0);
    }
    rec_msg->recBuf = (unsigned char *)malloc(attr.mq_msgsize);
    memset(rec_msg->recBuf, 0, attr.mq_msgsize);
    char *buff = (char *)malloc(attr.mq_msgsize);
    memset(buff, 0, attr.mq_msgsize);
    /* struct timespec ts = {
         .tv_sec = 5,
         .tv_nsec = 0};  */
    pthread_t tid = -1;
    int len = -1;
    pthread_detach(pthread_self());
    printf("%s thread start\n", __func__);
    while (1)
    {
        //  len = mq_timedreceive(rec_msg->recPosix->mqd, buff, attr.mq_msgsize, 0, &ts);
        len = mq_receive(rec_msg->recPosix->mqd, buff, attr.mq_msgsize, 0);
        printf("%s|%s|%d:len = %d\n", __FILE__, __func__, __LINE__, len);
        printf("%s|%s|%d:rec->0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\n", __FILE__, __func__, __LINE__, buff[0],
               buff[1], buff[2], buff[3], buff[4], buff[5]);
        if (-1 == len)
        {
            if (errno == EAGAIN)
            {
                fprintf(stderr, "No messages available and O_NONBLOCK is set.\n");
                continue;
            }
            else if (errno == ETIMEDOUT)
            {
                fprintf(stderr, "No messages available and timeout.\n");
                continue;
            }
            else
            {
                perror("mq_timedreceive");
                break;
            }
        }
        else if (0 < len && buff[0] == 0xAA && buff[1] == 0x55 &&
                 buff[4] == 0x55 && buff[5] == 0xAA)
        {
            rec_msg->recLen = len;
            memcpy(rec_msg->recBuf, buff, len);
            pthread_create(&tid, NULL, handle_device, (void *)rec_msg);
        }
    }
    free(rec_msg->recBuf);
    free(buff);
    pthread_exit(0);
}

listen_node rec_stu = {
    .listen_name = "receive",
    .init = rec_init,
    .final = rec_final,
    .get = rec_get,
    .set = NULL,
    .next = NULL};

listen_pt rec_add(listen_pt lisHead)
{
    return lis_add(lisHead, &rec_stu);
}